/* Copyright (C) 2010 Fredrique Samuels, fredriquesamuels@gmail.com */

/*
  This program is free software; you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation; either version 2 of the License, or
  (at your option) any later version.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this program; if not, write to the Free Software
  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

#include "xmlnode.h"


namespace tri{

TXMLValue::TXMLValue(std::string v):value(v){}
TXMLValue::~TXMLValue(){}

void TXMLValue::_getValue(int &v){v = utils::string2Int(value.c_str());}
void TXMLValue::_getValue(float &v){v = utils::string2Float(value.c_str());}
void TXMLValue::_getValue(std::string &v){v = std::string(value.c_str());}

void TXMLValue::setValue(std::string v){
    value = v;
}

TXMLNode::TXMLNode(char* value):TXMLValue(value),TXMLNodeTree(){}
TXMLNode::~TXMLNode(){}

bool TXMLNode::hasAttribute(std::string s){
    return attr.find(s)!=attr.end();
}

int TXMLNode::countAttribute(std::string s){
    if(hasAttribute(s)){
        return attr[s].size(); 
    }
    return 0;
}



void TXMLNode::addAttribute(std::string type,std::string value){
    if(!hasAttribute(type)){
        attr[type] = std::vector<TXMLValue>();
    }
    
    attr[type].push_back(TXMLValue(value));
}


TXMLNodeTree::TXMLNodeTree(){}
TXMLNodeTree::~TXMLNodeTree(){}

void TXMLNodeTree::setType(std::string type){
	this->type = type;
}

std::string TXMLNodeTree::getType(){
	return type;
}

bool TXMLNodeTree::hasElement(std::string s){
    
    return elem.find(s)!=elem.end();
}
int TXMLNodeTree::countElement(std::string s){
    if(hasElement(s)){
        return elem[s].size(); 
    }
    return 0;
}

TXMLNode* TXMLNodeTree::getElement(std::string s,int index){

    if(!hasElement(s)){ 
        throw TriXMLException("XML Element does not exists!!!\n");
    }
    if( index < 0){
        throw TriXMLException("XML Element Index cannot be less than 0!!!\n");
    }
    if( countElement(s) <= index){
        throw TriXMLException("XML Element Index out of range!!!\n");
    }
    
    return &elem[s][index];
}

void TXMLNodeTree::addElement(std::string type,char* value){

    if(!hasElement(type)){
        elem[type] = std::vector<TXMLNode>();
    }
    
    elem[type].push_back(TXMLNode(value));
    //elem[type][elem[type].size()-1].setType(type);
}


void TXMLNodeTree::loadElement(TiXmlNode* pParent,TXMLNode* node){
    if ( !pParent && node!= NULL) return;
    TiXmlNode* pChild;
    node->setType(pParent->Value());
    
    for ( pChild = pParent->FirstChild(); pChild != 0; pChild = pChild->NextSibling()) 
    {
        int t = pChild->Type();
        if (t==TiXmlNode::TINYXML_ELEMENT){
        
            TXMLNode* elem = NULL;
            const char* type = pChild->Value();
            node->addElement(type);
            TXMLNode* new_node = node->getElement(type,node->countElement(type)-1);
            TiXmlAttribute* pAttrib=((TiXmlElement*)pChild)->FirstAttribute();
            while (pAttrib)
            {
                new_node->addAttribute(pAttrib->Name(),pAttrib->Value());
                pAttrib=pAttrib->Next();
            }
            loadElement(pChild,new_node);
        }
        else if (t== TiXmlNode::TINYXML_TEXT){
            std::string text = std::string(pChild->ToText()->Value());
            node->setValue(text);
        }
    }

}

void TXMLNodeTree::loadXMLFromFile(const char* pFilename,TXMLNode* d){
    TiXmlDocument doc(pFilename);
    bool loadOkay = doc.LoadFile();
    if (loadOkay)
    {
        d->clear();
        TXMLNodeTree::loadElement(&doc,d);
    }
    else
    {
        throw TriXMLException("Failed to load file");
    }
}

void TXMLNodeTree::clear(){
    elem.clear();
}


TXMLDoc::TXMLDoc():TXMLNode(){}
TXMLDoc::~TXMLDoc(){clear();}
    
void TXMLDoc::load(const char* File){
    tri::TXMLNodeTree::loadXMLFromFile(File,this);
}


}
